package xyz.ibenben.zhongdian.system.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.*;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.multipart.MultipartFile;
import xyz.ibenben.zhongdian.common.annotation.SystemControllerLog;
import xyz.ibenben.zhongdian.common.constants.Constants;
import xyz.ibenben.zhongdian.system.entity.HistoryActivitiEntity;
import xyz.ibenben.zhongdian.system.entity.sys.SysUser;
import xyz.ibenben.zhongdian.system.form.ActForm;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author chenjian
 */
@Controller
@SessionAttributes("actForm")
@RequestMapping("/activiti")
public class ActivitiController {
    /**
     * 实体名称
     */
    private static final String ENTITYNAME = "activiti";
    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;

    public static SysUser getSysUser() {
        return (SysUser) SecurityUtils.getSubject().getSession().getAttribute(Constants.SESSION);
    }

    /**
     * 初始化
     *
     * @param map     参数
     * @param actForm 条件参数
     */
    @ModelAttribute
    public void init(Model map, @ModelAttribute ActForm actForm) {
        ActForm newActForm = new ActForm();
        if (null != actForm) {
            newActForm = actForm;
        }
        map.addAttribute(String.format(Constants.FORMNAME, ENTITYNAME), newActForm);
    }

    /**
     * 获取流程管理列表
     *
     * @param map     参数
     * @param actForm 条件参数
     * @return 页面
     */
    @RequestMapping(value = "/getAll")
    @SystemControllerLog(description = "获取流程管理列表")
    public String getAll(Model map, @ModelAttribute ActForm actForm) {
        map.addAttribute(String.format(Constants.FORMNAME, ENTITYNAME), actForm);
        Page<ProcessDefinition> page = new Page<>(actForm.getPageIndex(), actForm.getPageSize());
        ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
        if (StringUtils.isNotBlank(actForm.getTitle())) {
            query.processDefinitionNameLike(actForm.getTitle());
        }
        if (StringUtils.isNotBlank(actForm.getKey())) {
            query.processDefinitionKeyLike(actForm.getKey());
        }
        long count = query.count();
        page.setTotal(count);
        List<ProcessDefinition> processDefinitionList = query.latestVersion()
                .listPage(actForm.getPageIndex() - 1, actForm.getPageSize());
        page.setRecords(processDefinitionList);
        map.addAttribute(Constants.PI, page);
        return String.format(Constants.LISTPAGE, ENTITYNAME);
    }

    /**
     * @return String
     */
    @RequestMapping("/upload")
    public String upload() {
        return String.format(Constants.UPLOADPAGE, ENTITYNAME);
    }

    /**
     * 流程部署-- 导入方式
     *
     * @param file 文件
     */
    @PostMapping("/importProcess")
    public String importProcess(@RequestParam("file") MultipartFile file) {
        try {
            //获取流程定义和部署对象相关的Service 完成部署
            Deployment deployment = repositoryService
                    .createDeployment()//创建部署对象
                    .name("请假流程-EL")
                    .addInputStream("请假复杂流程-EL.bpmn", file.getInputStream())
                    .deploy();
            //1
            System.out.println("部署ID：" + deployment.getId());
            System.out.println("部署Name：" + deployment.getName());
            System.out.println("部署时间：" + deployment.getDeploymentTime());
            return String.format(Constants.REDIRECT, ENTITYNAME);
        } catch (Exception e) {
            e.printStackTrace();
            return String.format(Constants.UPLOADPAGE, ENTITYNAME);
        }
    }

    /**
     * 删除流程管理记录
     *
     * @param id 主键
     * @return 页面
     */
    @RequestMapping(value = "/delete")
    @SystemControllerLog(description = "删除流程管理记录")
    public String delete(@RequestParam("id") String id, SessionStatus status) {
        repositoryService.deleteDeployment(id, true);
        status.setComplete();
        return String.format(Constants.REDIRECT, ENTITYNAME);
    }

    /**
     * 删除流程管理列表
     *
     * @param actForm 条件参数
     * @return 页面
     */
    @RequestMapping("/deleteAll")
    @SystemControllerLog(description = "删除流程管理列表")
    public String deleteAll(@ModelAttribute ActForm actForm, SessionStatus status) {
        if (actForm.getSelectIds() != null) {
            String[] ids = actForm.getSelectIds().split(Constants.COMMA);
            for (String id : ids) {
                repositoryService.deleteDeployment(id, true);
            }
        }
        status.setComplete();
        return String.format(Constants.REDIRECT, ENTITYNAME);
    }

    /**
     * 一键删除
     *
     * @return 结果
     */
    @RequestMapping("/oneDelete")
    @ResponseBody
    public String oneDelete() {
        List<Deployment> list = repositoryService.createDeploymentQuery().list();
        list.forEach(e -> repositoryService.deleteDeployment(e.getId(), true));
        return String.format(Constants.REDIRECT, ENTITYNAME);
    }

    /**
     * 打开添加流程页面
     *
     * @return 页面
     */
    @GetMapping("/add")
    @SystemControllerLog(description = "打开添加流程页面")
    public String openAddPage() {
        return String.format(Constants.ADDPAGE, ENTITYNAME);
    }

    @RequestMapping("/newProBefore")
    public String newProBefore() {
        return "activiti/form";
    }

    /**
     * 工作流  流程图 查看
     *
     * @return String
     */
    @RequestMapping("/view")
    public String view(Model map, String instanceId) {
        map.addAttribute("instanceId", instanceId);
        return String.format(Constants.VIEWPAGE, ENTITYNAME);
    }

    @RequestMapping("/getApply_status")
    @ResponseBody
    public Map<String, Object> getApplyStatus(String instanceId) {
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(instanceId).singleResult();
        if (historicProcessInstance != null) {

            //获取bpmnModel对象
            BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
            //因为我们这里只定义了一个Process 所以获取集合中的第一个即可
            Process process = bpmnModel.getProcesses().get(0);
            //获取所有的FlowElement信息
            Collection<FlowElement> flowElements = process.getFlowElements();

            Map<String, String> map = new HashMap<>();
            for (FlowElement flowElement : flowElements) {
                //判断是否是连线
                if (flowElement instanceof SequenceFlow) {
                    SequenceFlow sequenceFlow = (SequenceFlow) flowElement;
                    String ref = sequenceFlow.getSourceRef();
                    String targetRef = sequenceFlow.getTargetRef();
                    map.put(ref + targetRef, sequenceFlow.getId());
                }
            }


            //获取流程实例 历史节点(全部)
            List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(instanceId)
                    .list();
            //各个历史节点   两两组合 key
            Set<String> keyList = new HashSet<>();
            for (HistoricActivityInstance i : list) {
                for (HistoricActivityInstance j : list) {
                    if (i != j) {
                        keyList.add(i.getActivityId() + j.getActivityId());
                    }
                }
            }
            //高亮连线ID
            Set<String> highLine = new HashSet<>();
            keyList.forEach(s -> highLine.add(map.get(s)));

            //获取流程实例 历史节点（已完成）
            List<HistoricActivityInstance> listFinished = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(instanceId)
                    .finished()
                    .list();
            //高亮节点ID
            Set<String> highPoint = new HashSet<>();
            listFinished.forEach(s -> highPoint.add(s.getActivityId()));

            //获取流程实例 历史节点（待办节点）
            List<HistoricActivityInstance> listUnFinished = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(instanceId)
                    .unfinished()
                    .list();

            //需要移除的高亮连线
            Set<String> set = new HashSet<>();
            //待办高亮节点
            Set<String> waitingToDo = new HashSet<>();
            listUnFinished.forEach(s -> {
                waitingToDo.add(s.getActivityId());

                for (FlowElement flowElement : flowElements) {
                    //判断是否是 用户节点
                    if (flowElement instanceof UserTask) {
                        UserTask userTask = (UserTask) flowElement;

                        if (userTask.getId().equals(s.getActivityId())) {
                            List<SequenceFlow> outgoingFlows = userTask.getOutgoingFlows();
                            //因为 高亮连线查询的是所有节点  两两组合 把待办 之后  往外发出的连线 也包含进去了  所以要把高亮待办节点 之后 即出的连线去掉
                            if (outgoingFlows != null && outgoingFlows.size() > 0) {
                                outgoingFlows.forEach(a -> {
                                    if (a.getSourceRef().equals(s.getActivityId())) {
                                        set.add(a.getId());
                                    }
                                });
                            }
                        }
                    }
                }
            });
            highLine.removeAll(set);

            //获取当前用户
            SysUser sysUser = getSysUser();
            //存放 高亮 我的办理节点
            Set<String> iDo = new HashSet<>();
            //当前用户已完成的任务
            List<HistoricTaskInstance> taskInstanceList = historyService.createHistoricTaskInstanceQuery()
                    .taskAssignee(sysUser.getUsername())
                    .finished()
                    .processInstanceId(instanceId).list();
            taskInstanceList.forEach(a -> iDo.add(a.getTaskDefinitionKey()));
            Map<String, Object> reMap = new HashMap<>();
            reMap.put("highPoint", highPoint);
            reMap.put("highLine", highLine);
            reMap.put("waitingToDo", waitingToDo);
            reMap.put("iDo", iDo);
            return reMap;
        }
        return null;
    }

    @RequestMapping("/hisWork")
    public String hisWork(Model model, @ModelAttribute ActForm actForm) {
        SysUser sysUser = getSysUser();
        List<HistoryActivitiEntity> list = new ArrayList<>();
        Page<HistoryActivitiEntity> page = new Page<>(actForm.getPageIndex(), actForm.getPageSize());
        HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery();
        if (StringUtils.isNotBlank(actForm.getTitle())) {
            query.processDefinitionNameLike(actForm.getTitle());
        }
        if (StringUtils.isNotBlank(actForm.getKey())) {
            query.processDefinitionKeyLike(actForm.getKey());
        }
        long count = query.taskAssignee(sysUser.getUsername()).count();
        page.setTotal(count);
        List<HistoricTaskInstance> historicTaskInstances = query.taskAssignee(sysUser.getUsername())
                .listPage(actForm.getPageIndex() - 1, actForm.getPageSize());
        historicTaskInstances.forEach(s -> {
            HistoricProcessInstance his = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(s.getProcessInstanceId()).singleResult();
            HistoryActivitiEntity entity = new HistoryActivitiEntity();
            entity.setName(s.getName());
            entity.setStartTime(his.getStartTime());
            entity.setId(his.getId());
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(his.getId())
                    .singleResult();
            if (processInstance == null) {
                entity.setStatus("已完成");
            } else {
                entity.setStatus("执行中");
            }
            list.add(entity);
        });
        page.setRecords(list);
        model.addAttribute(Constants.PI, page);
        return "activiti/hisWork";
    }

    /**
     * 工作流  流程图  个人流程查看
     *
     * @return ModelAndView
     */
    @RequestMapping("/hisView")
    public String applyMyView(Model map, String instanceId) {
        map.addAttribute("instanceId", instanceId);
        return "activiti/hisView";
    }

    /**
     * 我的待办
     *
     * @return 结果
     */
    @RequestMapping("/waitingList")
    public String waitingList(Model model, @ModelAttribute ActForm actForm) {
        SysUser sysUser = getSysUser();
        List<HistoryActivitiEntity> list = new ArrayList<>();
        Page<HistoryActivitiEntity> page = new Page<>(actForm.getPageIndex(), actForm.getPageSize());
        TaskQuery query = taskService.createTaskQuery();
        long count = query.processDefinitionKey("process_leave").count();
        List<Task> taskList = query.processDefinitionKey("process_leave")
                .listPage(actForm.getPageIndex() - 1, actForm.getPageSize());
        if (null != taskList && !taskList.isEmpty()) {
            for (Task task : taskList) {
                taskService.claim(task.getId(), sysUser.getUsername());
            }
            HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery()
                    .variableName("user").taskId(taskList.get(0).getId()).singleResult();
            String username = (String) historicVariableInstance.getValue();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            for (Task t : taskList) {
                HistoryActivitiEntity entity = new HistoryActivitiEntity();
                t.setDescription(username + "-请假申请单-" + sdf.format(t.getCreateTime()));
                entity.setDescription(username + "-请假申请单-" + sdf.format(t.getCreateTime()));
                entity.setName(t.getName());
                entity.setExecutionId(t.getExecutionId());
                if (t.getOwner() != null && !"null".equals(t.getOwner())) {
                    entity.setStatus(t.getDelegationState().name());
                } else {
                    entity.setStatus("执行中");
                }
                entity.setId(t.getId());
                list.add(entity);
            }
        }
        page.setTotal(count);
        page.setRecords(list);
        model.addAttribute(Constants.PI, page);
        return "activiti/waitingList";
    }

    /**
     * 我的申请
     *
     * @param model   查询
     * @param actForm 条件
     * @return 结果
     */
    @RequestMapping("/applyList")
    public String myApplyList(Model model, @ModelAttribute ActForm actForm) {
        SysUser sysUser = getSysUser();
        List<HistoryActivitiEntity> list = new ArrayList<>();
        Page<HistoryActivitiEntity> page = new Page<>(actForm.getPageIndex(), actForm.getPageSize());
        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery();
        if (StringUtils.isNotBlank(actForm.getTitle())) {
            query.processInstanceNameLike(actForm.getTitle());
        }
        if (StringUtils.isNotBlank(actForm.getKey())) {
            query.processInstanceBusinessKey(actForm.getKey());
        }
        long count = query.startedBy(sysUser.getUsername()).count();
        page.setTotal(count);
        List<HistoricProcessInstance> historicProcessInstances = query.startedBy(sysUser.getUsername())
                .listPage(actForm.getPageIndex() - 1, actForm.getPageSize());
        historicProcessInstances.forEach(s -> {
            HistoryActivitiEntity entity = new HistoryActivitiEntity();
            entity.setName(s.getStartUserId() + "_" + s.getProcessDefinitionName());
            entity.setStartTime(s.getStartTime());
            entity.setId(s.getId());
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(s.getId()).singleResult();
            if (processInstance == null) {
                entity.setStatus("已完成");
            } else {
                entity.setStatus("执行中");
            }
            list.add(entity);
        });
        page.setRecords(list);
        model.addAttribute(Constants.PI, page);
        return "activiti/applyList";
    }

    /**
     * 工作流  流程图 查看
     *
     * @return String
     */
    @RequestMapping("/applyView")
    public String applyView(Model map, String instanceId) {
        map.addAttribute("instanceId", instanceId);
        return "activiti/applyView";
    }

    @RequestMapping("/approvalMsg")
    public String approvalPass(String instanceId, String msg) {
        if (StringUtils.isNotEmpty(msg)) {
            String str = msg.replace("\"", "");
            taskService.setVariable(instanceId, "msg", str);
        }
        taskService.complete(instanceId);
        return "redirect:/activiti/waitingList";
    }
}
